﻿using System.Reflection;
using AntQuartzUI.Attributes;
using AntQuartzUI.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Quartz;

namespace AntQuartzUI.Extension;

public static class AntQuartzUiExtension
{
    private static string defaultSchedulerId = "AntQuartUI.Default";

    /// <summary>
    /// 引入UI包
    /// </summary>
    /// <param name="services"></param>
    public static void AddAntQuartzUi(this IServiceCollection services)
    {
        services.AddRazorPages();
        services.AddTransient<IQuartzService, QuartzService>();
        
        var allAttrDic = new Dictionary<Type,QuartzTriggerAttribute>(); 
        var allTypeList = new List<Type>();  // id，类
        
        foreach (var assembly in Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
                     .Where(x =>
                         !x.StartsWith("System")
                         && !x.StartsWith("Microsoft")
                         && !x.StartsWith("netstandard")
                         && !x.StartsWith("System.Private")
                         && !x.StartsWith("System.Runtime")
                         && !x.StartsWith("System.Diagnostics")
                         && !x.StartsWith("System.Net")
                         && !x.StartsWith("System.Xml")
                         && !x.StartsWith("WindowsBase")
                         && !x.StartsWith("System.Security")
                         && !x.StartsWith("Microsoft.Win32")
                         && !x.StartsWith("System.Threading")
                         && !x.StartsWith("Azure")
                         && !x.StartsWith("Microsoft.IdentityModel")
                     )
                     .Select(x =>
                     {
                         try
                         {
                             return Assembly.Load(AssemblyName.GetAssemblyName(x));
                         }
                         catch (Exception ex)
                         {
                             // 记录错误，或者直接跳过该文件
                             Console.WriteLine($"Failed to load assembly {x}: {ex.Message}");
                             return null; // 返回 null 表示失败，后续过滤掉这些 null
                         }
                     })
                     .Where(a => a != null) // 过滤掉 null 值（加载失败的程序集）
                     .ToList())
        {
            if (assembly is null) continue;
            // 筛选包含服务
            var serverClasses = assembly.GetTypes()
                .Where(x => x is { IsClass: true, IsAbstract: false } && typeof(IJob).IsAssignableFrom(x) &&
                            x.GetCustomAttributes().Any(y => y.GetType() == typeof(QuartzTriggerAttribute)));
            var classes = serverClasses as Type[] ?? serverClasses.ToArray();
            if (classes.Length == 0) continue;
            
            foreach (var @class in classes)
            {
                var attribute = @class.GetCustomAttributes()
                    .Where(y => y.GetType() == typeof(QuartzTriggerAttribute)).OfType<QuartzTriggerAttribute>()
                    .Single();
                
                allAttrDic.Add(@class, attribute);
                allTypeList.Add( @class);
            }
        }

        services.Configure<QuartzOptions>(options =>
        {
            options.SchedulerId = defaultSchedulerId;
            options.Scheduling.IgnoreDuplicates = true;
            options.Scheduling.OverWriteExistingData = true;
            
            foreach (var type in allTypeList)
            {
                var attribute = allAttrDic[type];
                var jobKey = new JobKey(
                    string.IsNullOrWhiteSpace(attribute.JobName) ? type.Name : attribute.JobName,
                    string.IsNullOrWhiteSpace(attribute.JobGroupName) ? $"{type.Name}Group" : attribute.JobGroupName);
        
                options.AddJob(type, job =>
                    job.WithIdentity(jobKey)
                        .WithDescription(attribute.Describe)
                        .Build()
                );
        
                options.AddTrigger(builder =>
                {
                    builder.StartNow()
                        .WithIdentity("Trigger_1",nameof(type.FullName))
                        .WithSimpleSchedule(x =>
                            x.WithIntervalInSeconds(attribute.Second)
                                .RepeatForever())
                        .ForJob(jobKey)
                        .Build();
                });
            }
        });
        
        services.AddQuartz(options =>
        {
            options.SchedulerId = defaultSchedulerId;
            options.SchedulerName = defaultSchedulerId;
            options.AddTriggerListener<TriggerExecutionMonitor>();
            options.AddJobListener<JobExecutionMonitor>();
        });
        services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true);
        
        services.AddSingleton<IQuartzService, QuartzService>();
    }
    
    public static void UseAntQuartzUi(this WebApplication app)
    {
        app.UseStaticFiles();
        app.MapRazorPages();
    }
    
}